/*
* Copyright (c) 20FIX_KEY_LENGTH.2，华乘电气科技有限公司
* All rights reserved.
*
* 文件名称：AesCrypto.h
*
* 初始版本：1.0
* 作者：
* 创建日期：20FIX_KEY_LENGTH年2月26日
* 摘要：该文件主要是实现基于AES的加密模块
*
*/
#include <QDebug>
#include "AesCrypto.h"

const quint8 FIX_KEY_LENGTH = 16;//固定密钥FIX_KEY_LENGTH byte
/************************************************
 * 函数名    :AesCrypto
 * 输入参数  ：
 *      strKey -- 密钥
 * 输出参数  ：NULL
 * 返回值   ：NULL
 * 功能     ：构造函数
 ************************************************/
AesCrypto::AesCrypto( QByteArray baKey )
{
    QByteArray key = baKey;
    if( key.size() != FIX_KEY_LENGTH )
    {
        char keys[ FIX_KEY_LENGTH + 1 ] = "\0";
        for( int i = 0; i < FIX_KEY_LENGTH; i++ )
        {
            keys[i] = key.at(i % key.size());
        }
        keys[FIX_KEY_LENGTH] = '\0';
        crijndael.MakeKey(keys,"");
    }
    else
    {
        crijndael.MakeKey(key.data(),"");
    }
}

/************************************************
 * 函数名    :enCrypt
 * 输入参数  ：
 *      data -- 需要加密的数据
 * 输出参数  ：NULL
 * 返回值   ：
 *      加密后的数据
 * 功能     ：加密
 ************************************************/
QByteArray AesCrypto::enCrypt( const QByteArray& data )
{
    QByteArray dataBlock;
    QByteArray dataOut;
    QByteArray dataEncrypt;

    //待加密字节数
    int iLength = data.size();
    //块数
    int iBlockNum = iLength/FIX_KEY_LENGTH;

    //补齐
    if( iLength % FIX_KEY_LENGTH > 0 )
    {
        iBlockNum++;
    }
    //构造加密块,padding方式为PKCS7,加密过程中，使用的块
    dataBlock.fill( 0x00, iBlockNum*FIX_KEY_LENGTH+1 );
    memcpy( dataBlock.data(), data.data(), iLength );

    //padding块前一部分长度
    int k = iLength%FIX_KEY_LENGTH;
    //不padding块数
    int j = iLength/FIX_KEY_LENGTH;
    //padding块后一部分长度
    int iLenPadding = FIX_KEY_LENGTH - k;
    for( int i=0; i<iLenPadding; i++ )
    {
        dataBlock[ j*BLOCK_SIZE + k + i ] = iLenPadding;
    }
    dataBlock[ j*BLOCK_SIZE + k + iLenPadding ] = '\0';
    //padding 结束

    //加密后的密文
    dataOut.fill( 0, iBlockNum*FIX_KEY_LENGTH+1 );

    //加密字符串
    crijndael.Encrypt( dataBlock.data(), dataOut.data(), iBlockNum*FIX_KEY_LENGTH );

    dataEncrypt = QByteArray(dataOut, iBlockNum*FIX_KEY_LENGTH).toHex();

    return dataEncrypt;

}

/************************************************
 * 函数名    :deCrypt
 * 输入参数  ：
 *      data -- 需要解密的数据
 * 输出参数  ：NULL
 * 返回值   ：
 *      解密后的数据
 * 功能     ：解密
 ************************************************/
QByteArray AesCrypto::deCrypt( const QByteArray& data )
{
    QByteArray dataDecrypt;

    QByteArray dataHex = QByteArray::fromHex(data);

    int iLength = dataHex.size() + 1;

    QByteArray dataOut;
    dataOut.resize( iLength * 2 );

    crijndael.Decrypt( dataHex.data(), dataOut.data(), iLength - 1 );
    int max = 0;
    for(int i = iLength - 2; i > -1; i-- )
    {
        if(dataOut[i] <= '\x10' && dataOut[i] >= '\x00')
        {
            dataOut[i] = 0;
            max++;
        }
        else
        {
            break;
        }
    }
    dataDecrypt = QByteArray( dataOut, iLength - max );

    return dataDecrypt;
}
